package com.xc.quickstart.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.nacos.api.config.annotation.NacosValue;
import com.xc.quickstart.api.query.LoginQuery;
import com.xc.quickstart.api.vo.UserInfoVO;
import com.xc.quickstart.common.constant.ConfigKeyConstant;
import com.xc.quickstart.common.constant.ConfigTypeConstant;
import com.xc.quickstart.common.constant.RedisKeyConstant;
import com.xc.quickstart.common.context.ApiContext;
import com.xc.quickstart.common.context.CommonContext;
import com.xc.quickstart.common.exception.CommonBizException;
import com.xc.quickstart.infrastructure.redis.RedisService;
import com.xc.quickstart.common.util.JwtUtil;
import com.xc.quickstart.manager.sso.SsoManager;
import com.xc.quickstart.manager.wechat.QyWechatManager;
import com.xc.quickstart.mapper.entity.CrmAdminENT;
import com.xc.quickstart.service.AuthorityBizService;
import com.xc.quickstart.service.CrmAdminService;
import com.xc.quickstart.service.CrmConfigService;
import com.xc.quickstart.service.LoginBizService;
import jodd.time.TimeUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.DateUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class LoginBizServiceImpl implements LoginBizService {

    @Autowired
    private RedisService redisService;

    @Autowired
    private CrmAdminService crmAdminService;

    @Autowired
    private CrmConfigService crmConfigService;

    @Autowired
    private AuthorityBizService authorityBizService;


    @Autowired
    private SsoManager ssoManager;

    @Autowired
    private QyWechatManager qyWechatManager;

    @Autowired
    @Lazy
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;


    @NacosValue(value = "${user.whitelist:}", autoRefreshed = true)
    private String userWhitelist;

    @Override
    public boolean checkToken(String userId, String jobNumber, String token) {
        String key = String.format(RedisKeyConstant.TOKEN_KEY, userId, jobNumber);
        if (!redisService.exists(key)) {
            return false;
        }
        String value = redisService.get(key);
        if (token.equals(value)) {
            Long pttl = redisService.pttl(key);
            if (pttl <= DateUtil.SECONDS_PER_DAY * 2) {
                redisService.expire(key, TimeUtil.SECONDS_IN_DAY * 7);
            }
            return true;
        }
        return false;
    }

    @Override
    public String getSmsCode(String mobile) {
        String key = String.format(RedisKeyConstant.SMS_CODE_CHECK_KEY, mobile);
        if (redisService.exists(key) && Integer.parseInt(redisService.get(key)) >= 3) {
            log.warn("[获取验证码失败]手机号: {},验证结果: {}", mobile, "获取验证码太频繁，请稍后再试");
            return "获取验证码太频繁，请稍后再试";
        }
        String result = ssoManager.getSmsCode(mobile);
        if(StringUtils.isNotEmpty(result)){
            return result;
        }
        redisService.incr(key);
        redisService.expire(key, 60);
        return "获取验证码成功";
    }

    @Override
    public UserInfoVO loginWithSmsCode(LoginQuery loginDTO) {
        //白名单登录逻辑
        Set<String> userWhiteSet = getUserWhiteSet(userWhitelist);
        if (CollectionUtils.isNotEmpty(userWhiteSet) &&
                userWhiteSet.contains(String.format("%s:%s", loginDTO.getMobile(), loginDTO.getCode()))) {
            CrmAdminENT crmAdminENT = crmAdminService.getByMobile(loginDTO.getMobile());
            if (null != crmAdminENT) {
                return getUserInfoVO(crmAdminENT.getJobNumber(), Collections.singletonList(CommonContext.MERCHANT_MAP));
            }
        }

        //sso登录逻辑
        UserInfoVO userLoginInfoVO = ssoManager.loginWithSmsCode(loginDTO);
        if (CollUtil.isEmpty(userLoginInfoVO.getAllowmchids())) {
            throw new CommonBizException("未配置[海豚系统权限]，请确保已申请开通");
        }

        return getUserInfoVO(userLoginInfoVO.getJobNumber(), userLoginInfoVO.getAllowmchids());
    }

    private UserInfoVO getUserInfoVO(String jobNumber, List<Map<String, String>> allowmchids) {
        CrmAdminENT crmAdminENT = crmAdminService.get(jobNumber);
        if (Objects.isNull(crmAdminENT)) {
            throw new CommonBizException("账号不存在！");
        }

        UserInfoVO userInfoVO = wrapUserInfoVO(crmAdminENT);
        userInfoVO.setAllowmchids(allowmchids);

        String redisKey = String.format(RedisKeyConstant.TOKEN_KEY, crmAdminENT.getUserId(), crmAdminENT.getJobNumber());
        String token = JwtUtil.create(crmAdminENT.getUserId().toString(), crmAdminENT.getJobNumber(), crmAdminENT.getUserName(), TimeUtil.MILLIS_IN_DAY * 7);
        redisService.setex(redisKey, token, 7L, TimeUnit.DAYS);

        userInfoVO.setToken(token);

        //删除缓存
        threadPoolTaskExecutor.execute(() -> authorityBizService.clear(crmAdminENT.getXcmchid(),userInfoVO.getJobNumber()));

        return userInfoVO;
    }

    @Override
    public UserInfoVO getUserInfo() {
        String jobNumber = ApiContext.getApiContextModel().getJobNumber();
        CrmAdminENT crmAdminENT = crmAdminService.get(jobNumber);

        if (Objects.isNull(crmAdminENT)) {
            throw new CommonBizException("账号不存在！");
        }

        return wrapUserInfoVO(crmAdminENT);
    }

    @Override
    public UserInfoVO qyWechatLogin(String authorizationCode) {
        String accessToken = qyWechatManager.getAccessToken();
        String jobNumber = qyWechatManager.getJobNumber(accessToken, authorizationCode);
        return getUserInfoVO(jobNumber, Collections.singletonList(CommonContext.MERCHANT_MAP));
    }

    private UserInfoVO wrapUserInfoVO(CrmAdminENT crmAdminENT) {
        List<String> currentENTList = crmConfigService.getCurrentENTList(ConfigKeyConstant.ADMIN_JOBNUMBER, ConfigTypeConstant.CRM, String.class);

        UserInfoVO userInfoVO = new UserInfoVO();
        userInfoVO.setMobile(crmAdminENT.getMobile());
        userInfoVO.setJobNumber(crmAdminENT.getJobNumber());
        userInfoVO.setUserId(crmAdminENT.getUserId());
        userInfoVO.setUserName(crmAdminENT.getUserName());
        userInfoVO.setManagerLevel(crmAdminENT.getManagerLevel());
        userInfoVO.setManagerName(crmAdminENT.getManagerName());
        userInfoVO.setDepartId(crmAdminENT.getDeptId());
        userInfoVO.setDepartName(crmAdminENT.getDeptName());
        userInfoVO.setDeptParentId(crmAdminENT.getDeptParentId());
        userInfoVO.setDeptParentName(crmAdminENT.getDeptParentName());
        userInfoVO.setAdminUser(currentENTList.contains(crmAdminENT.getJobNumber()));
        return userInfoVO;
    }


    private Set<String> getUserWhiteSet(String userWhitelist) {
        if (StringUtils.isEmpty(userWhitelist)) {
            return Collections.emptySet();
        }

        return new HashSet<>(Arrays.asList(userWhitelist.split(",")));
    }
}
